﻿using System;
using System.Diagnostics;

namespace SfsTools.Core
{
    /// <summary>
    /// Contains parameters that specify the layout of the <see cref="FileSystem"/> created on a <see cref="IVolume"/>.
    /// </summary>
    public class FileSystemCreationParameters : Object, ICloneable
    {
        #region Properties

        /// <summary>
        /// Contains the block size.
        /// </summary>
        private Int32 FBlockSize;
        /// <summary>
        /// Gets or sets the block size.
        /// </summary>
        public Int32 BlockSize
        {
            [DebuggerStepThrough]
            get
            {
                return FBlockSize;
            }
            [DebuggerStepThrough]
            set
            {
                int index;
                for (index = 0; index < 31; index++)
                {
                    if (value == (1 << index))
                        break;
                }
                if (index >= 31)
                    throw new BlockSizeNotPowerOfTwoException("value");
                if (index < 8)
                    throw new BlockSizeTooSmallPowerOfTwoException("value");
                if (index > 24)
                    throw new BlockSizeTooLargePowerOfTwoException("value");
                FBlockSize = value;
            }
        }

        /// <summary>
        /// Contains the size of the volume, in bytes.
        /// </summary>
        private Int64 FVolumeSize;
        /// <summary>
        /// Gets or sets the size of the volume, in bytes.
        /// </summary>
        /// <remarks>A value of <em>-1</em> means <em>use a best guess</em>.</remarks>
        /// <exception cref="ArgumentOutOfRangeException">The argument <paramref name="value"/> is not valid.</exception>
        public Int64 VolumeSize
        {
            [DebuggerStepThrough]
            get
            {
                return FVolumeSize;
            }
            [DebuggerStepThrough]
            set
            {
                if (value < -1)
                    throw new ArgumentOutOfRangeException("value");
                FVolumeSize = value;
            }
        }

        /// <summary>
        /// Contains the size of the data area, in bytes.
        /// </summary>
        private Int64 FDataAreaSize;
        /// <summary>
        /// Gets or sets the size of the data area, in bytes.
        /// </summary>
        /// <remarks>A value of <em>-1</em> means <em>use a best guess</em>.</remarks>
        /// <exception cref="ArgumentOutOfRangeException">The argument <paramref name="value"/> is not valid.</exception>
        public Int64 DataAreaSize
        {
            [DebuggerStepThrough]
            get
            {
                return FDataAreaSize;
            }
            [DebuggerStepThrough]
            set
            {
                if (value < -1)
                    throw new ArgumentOutOfRangeException("value");
                FDataAreaSize = value;
            }
        }

        /// <summary>
        /// Contains the size of the index area, in bytes.
        /// </summary>
        private Int64 FIndexAreaSize;
        /// <summary>
        /// Gets or sets the size of the index area, in bytes.
        /// </summary>
        /// <remarks>A value of <em>-1</em> means <em>use a best guess</em>.</remarks>
        /// <exception cref="ArgumentOutOfRangeException">The argument <paramref name="value"/> is not valid.</exception>
        public Int64 IndexAreaSize
        {
            [DebuggerStepThrough]
            get
            {
                return FIndexAreaSize;
            }
            [DebuggerStepThrough]
            set
            {
                if (value < -1)
                    throw new ArgumentOutOfRangeException("value");
                FIndexAreaSize = value;
            }
        }

        /// <summary>
        /// Contains the size of the reserved area, in bytes.
        /// </summary>
        private Int64 FReservedAreaSize;
        /// <summary>
        /// Gets or sets the size of the reserved area, in bytes.
        /// </summary>
        /// <remarks>A value of <em>-1</em> means <em>use a best guess</em>.</remarks>
        /// <exception cref="ArgumentOutOfRangeException">The argument <paramref name="value"/> is not valid.</exception>
        public Int64 ReservedAreaSize
        {
            [DebuggerStepThrough]
            get
            {
                return FReservedAreaSize;
            }
            [DebuggerStepThrough]
            set
            {
                if (value < -1)
                    throw new ArgumentOutOfRangeException("value");
                FReservedAreaSize = value;
            }
        }

        #endregion

        #region Constructors
        /// <overloads>Initializes a new instance of <see cref="FileSystemCreationParameters"/>.</overloads>
        /// <summary>
        /// Initializes a new instance of <see cref="FileSystemCreationParameters"/>.
        /// </summary>
        [DebuggerStepThrough]
        public FileSystemCreationParameters()
            : base()
        {
            FBlockSize = 512;
            FVolumeSize = 1440 * 1024;
            FReservedAreaSize = -1;
            FDataAreaSize = -1;
            FIndexAreaSize = -1;
        }
        /// <summary>
        /// Initializes a new instance of <see cref="FileSystemCreationParameters"/> from an existing instace.
        /// </summary>
        /// <param name="value">The instance to copy.</param>
        /// <exception cref="ArgumentNullException">The argument <paramref name="value"/> is <see langword="null"/>.</exception>
        [DebuggerStepThrough]
        public FileSystemCreationParameters(FileSystemCreationParameters value)
            : base()
        {
            if (value == null)
                throw new ArgumentNullException("value");
            // ReSharper disable RedundantThisQualifier
            this.FBlockSize = value.FBlockSize;
            this.FDataAreaSize = value.FDataAreaSize;
            this.FIndexAreaSize = value.FIndexAreaSize;
            this.FReservedAreaSize = value.FReservedAreaSize;
            this.FVolumeSize = value.FVolumeSize;
            // ReSharper restore RedundantThisQualifier
        }
        #endregion
                
        #region ICloneable Members
        
        /// <summary>
        /// Creates a new <see cref="FileSystemCreationParameters"/> that is the copy of the current instance.
        /// </summary>
        /// <returns>A new <see cref="FileSystemCreationParameters"/> that is the copy of the current instance.</returns>
        [DebuggerStepThrough]
        public virtual FileSystemCreationParameters Clone()
        {
            return new FileSystemCreationParameters(this);
        }
        
        /// <summary>
        /// Creates a new <see cref="FileSystemCreationParameters"/> that is the copy of the current instance.
        /// </summary>
        /// <returns>A new <see cref="FileSystemCreationParameters"/> that is the copy of the current instance.</returns>
        [DebuggerStepThrough]
        object ICloneable.Clone()
        {
            return Clone();
        }
        
        #endregion
    }
}
